﻿// ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Local
// ReSharper disable MemberCanBePrivate.Local
// ReSharper disable FieldCanBeMadeReadOnly.Local

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;

namespace Pixeldyne.Core.Network
{
	/// <summary>
	/// Network tools.
	/// </summary>
	public class Networking
	{
		public static PingReply Ping(string address, int timeout, int packetSize = 32, int ttl = 128)
		{
			var characters = new char[packetSize];
			for (int i = 0; i < characters.Length; i++)
				characters[i] = 'X';

			byte[] packetData = Encoding.ASCII.GetBytes(characters);

			var pingSender = new Ping();

			var packetOptions = new PingOptions(ttl, true);

			PingReply reply = pingSender.Send(address, timeout, packetData, packetOptions);

			return reply;
		}

		/// <summary>
		/// Checks if a port is opened on a remote system.
		/// </summary>
		/// <param name="ipAddress">The IP address.</param>
		/// <param name="port">The port number 1 - 65535.</param>
		/// <param name="protocol">The protocol (either TCP or UDP).</param>
		/// <returns><c>true</c> if port is opened; otherwise, <c>false.</c>
		/// </returns>
		public static bool IsPortOpened(string ipAddress, int port, SocketOptionLevel protocol = SocketOptionLevel.Tcp)
		{
			var opened = false;

			switch (protocol)
			{
				case SocketOptionLevel.Tcp:
					using (var tcpClient = new TcpClient())
					{
						try
						{
							tcpClient.Connect(ipAddress, port);
							opened = true;
						}
						catch
						{
							opened = false;
						}
						finally
						{
							tcpClient.Close();
						}
					}
					break;
				case SocketOptionLevel.Udp:
					using (var udpClient = new UdpClient())
					{
						try
						{
							udpClient.Connect(ipAddress, port);
							opened = true;
						}
						catch
						{
							opened = false;
						}
						finally
						{
							udpClient.Close();
						}
					}
					break;
			}

			return opened;
		}

		#region Conversions
		/// <summary>
		/// Convert an IP string to its integer representation
		/// </summary>
		/// <param name="ip">Dotted IP address</param>
		/// <returns></returns>
		public static Int64 IPAddressStringToInt64(string ip)
		{
			if (string.IsNullOrEmpty(ip))
				return 0;

			string[] ipstring = ip.Split('.');

			return Calculate(ipstring);
		}

		private static uint Calculate(string[] ipStrings)
		{
			var ipBytes = new byte[ipStrings.Length];

			for (int i = 0; i < ipStrings.Length; i++)
				ipBytes[i] = byte.Parse(ipStrings[i]);

			return Calculate(ipBytes);
		}

		private static uint Calculate(byte[] ipBytes)
		{
			uint ipNumber = (uint)ipBytes[0] << 24;
			ipNumber += (uint)ipBytes[1] << 16;
			ipNumber += (uint)ipBytes[2] << 8;
			ipNumber += ipBytes[3];

			return ipNumber;
		}

		public static string Int64ToIPAddressString(long ip)
		{
			var oIP = new IPAddress(ip);
			byte[] byteIP = oIP.GetAddressBytes();

			uint ipNumber = Calculate(byteIP);

			return new IPAddress(ipNumber).ToString();
		}
		#endregion Conversions

		// ReSharper restore FieldCanBeMadeReadOnly.Local
		// ReSharper restore MemberCanBePrivate.Local
		// ReSharper restore UnusedMember.Local
		// ReSharper restore InconsistentNaming
	}
}


